export = {}

/** 1. `&` 实现 Intersection Types交叉类型
 *      交叉类型是取并集
 *      而联合类型 a|b, 其实是或
 *      没错, 就是这么操蛋
 *
 *      为什么这么设计？？
 *      你想一想我们 type C = A & B
 *      其实是希望这个 C 既能赋给 A
 *      又能赋给B
 *      也是就是说C既要包含A又要包含B的属性才行,
 *      这也是为什么反直觉的原因
 */
/** case1.1*/
interface A {
  name: string;
  age: number;
}

interface B {
  name: string;
  grade: number;
}

const c: A & B = {
  name: 'c',
  age:18,
  grade: 100,
  // afwfw:'wfwf' //TS2322: Type '{ name: string; age: number; grade: number; afwfw: string; }' is not assignable to type 'A & B'.   Object literal may only specify known properties, and 'afwfw' does not exist in type 'A & B'.
};
c.name
c.age
c.grade

/** 没有交集就是never*/
interface P{
  name:string
}
interface P2{
  name:number
}
type P3 = P&P2
let x:P3 = {name:123}  //TS2322: Type 'number' is not assignable to type 'never'.

/** 最常用的例子*/
function mixin<T,K>(obj1:T, obj2:K):T&K {
  return {...obj1,...obj2}
}
let r = mixin({a:1},{b:2})
r.b


/** case1.2*/
import * as React from 'react';

/** 报错↓*/
// const Layout: React.FunctionComponent = () => {
//   return (
//     <div></div>
//   );
// };
// Layout.Header; //TS2339: Property 'Header' does not exist on type 'FunctionComponent<{}>'.

/** 正确写法*/
/** 写法一*/
const Layout: React.FunctionComponent & { Header: React.FunctionComponent; } = () => {
  return (
    <div></div>
  );
};
Layout.Header = () => {
  return (
    <div>hi</div>
  );
};

interface Layout2 extends React.FunctionComponent{
  Header?: React.FunctionComponent;
}

/** 写法二*/
/* 接口名和变量名相同不会冲突,为什么可以这样呢？
 因为ts可以非常明确的知道,当你写layout2的时候,你到底指的是接口,还是值的变量
 如果你在`:`的后面或则`interface`关键字开头 很明显是类型 这不会弄错的*/
const Layout2: Layout2 = () => {
  return <div>div</div>;
};

Layout2.Header = () => {
  return <div>hi</div>
};


/* 其它例子
function extend<T, U>(first: T, second: U): T & U {
    let result = <T & U>{};
    for (let id in first) {
        (<any>result)[id] = (<any>first)[id];
    }
    for (let id in second) {
        if (!result.hasOwnProperty(id)) {
            (<any>result)[id] = (<any>second)[id];
        }
    }
    return result;
}

class Person {
    constructor(public name: string) { }
}
interface Loggable {
    log(): void;
}
class ConsoleLogger implements Loggable {
    log() {
        // ...
    }
}
var jim = extend(new Person("Jim"), new ConsoleLogger());
var n = jim.name;
jim.log();
*/
